home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Python1.4_Source / Lib / amigapath.py < prev    next >
Text File  |  1998-06-24  |  7KB  |  294 lines

  1. # Module 'amigapath' -- common operations on AMIGA pathnames
  2. # Irmen de Jong, april 1st, 1996 (no joke)
  3. # (adapted from `posixpath.py')
  4. #
  5. # 26-mar-96: fixed split, islink. Improved expanduser.
  6. # 1-apr-96: fixed expanduser (works 100% now)
  7. # 25-dec-96: slight changes to comments and expanduser.
  8. #
  9.  
  10. import amiga
  11. import stat
  12. import string
  13.  
  14. # normalize the case of a pathname
  15. normcase = string.lower
  16.  
  17.  
  18. # Return wheter a path is absolute. On Amiga: when a ':' occurs in it.
  19.  
  20. def isabs(s):
  21.     return ':' in s
  22.  
  23.  
  24. # Join two pathnames.
  25. # Ignore the first part if the second part is absolute.
  26. # Insert a '/' unless the first part is empty or already ends in '/' or ':'.
  27.  
  28. def join(a, b):
  29.     if ':' in b: return b
  30.     if a == '' or a[-1:] == '/': return a + b
  31.     # Note: join('x', '') returns 'x/'; is this what we want?
  32.     if a[-1:]==':': return a+b
  33.     return a + '/' + b
  34.  
  35.  
  36. # Split a path in head (everything up to the last '/' or ':') and tail (the
  37. # rest).  If the path ends in '/' or ':', tail will be empty.  If there is no
  38. # '/' or ':' in the path, head  will be empty.
  39. # DIFFERENCE WITH posixpath: only ONE trailing '/' will be stripped from head!
  40. # (on the Amiga a double slash means "parent dir"! ) This means that if
  41. # head ends in a '/', you MUST add a '/' to it when reconstructing the path,
  42. # or you will lose the "parent dir" slash.
  43. # Functions that depend on this function are also affected!
  44. #  (basename, dirname)
  45. #
  46. # Suggested by Kent Polk, kent@eaenki.nde.swri.edu
  47.  
  48. def split(p):
  49.     i = string.rfind(p, '/')
  50.     j = string.rfind(p, ':')
  51.     if (i>j) and p[-1]=='/':
  52.         p=p[:-1]
  53.         i = string.rfind(p, '/')
  54.     if (j>i) or ((j>=0) and (i<0)): i=j
  55.     head, tail = p[:i+1], p[i+1:]
  56.     if head:
  57.         if head[-1]=='/': head=head[:-1]
  58.     return head, tail
  59.  
  60.  
  61. # Split a path in root and extension.
  62. # The extension is everything starting at the last dot in the last
  63. # pathname component; the root is everything before that.
  64. # It is always true that root + ext == p.
  65.  
  66. def splitext(p):
  67.     root, ext = '', ''
  68.     for c in p:
  69.         if c == '/':
  70.             root, ext = root + ext + c, ''
  71.         elif c == '.':
  72.             if ext:
  73.                 root, ext = root + ext, c
  74.             else:
  75.                 ext = c
  76.         elif ext:
  77.             ext = ext + c
  78.         else:
  79.             root = root + c
  80.     return root, ext
  81.  
  82.  
  83. # Split a pathname into a drive specification and the rest of the
  84. # path.  Useful on DOS/Windows/NT/Amiga; on Unix, the drive is always empty.
  85.  
  86. def splitdrive(p):
  87.     i = string.rfind(p,':') + 1
  88.     if i<=0: return '', p
  89.     return p[:i],p[i:]
  90.  
  91.  
  92. # Return the tail (basename) part of a path.
  93.  
  94. def basename(p):
  95.     return split(p)[1]
  96.  
  97.  
  98. # Return the head (dirname) part of a path.
  99.  
  100. def dirname(p):
  101.     return split(p)[0]
  102.  
  103.  
  104. # Get the full pathname of a file/directory (i.e. expand assigns).
  105.  
  106. fullpath = amiga.fullpath
  107.  
  108.  
  109. # Return the longest prefix of all list elements.
  110.  
  111. def commonprefix(m):
  112.     if not m: return ''
  113.     prefix = m[0]
  114.     for item in m:
  115.         for i in range(len(prefix)):
  116.             if prefix[:i+1] <> item[:i+1]:
  117.                 prefix = prefix[:i]
  118.                 if i == 0: return ''
  119.                 break
  120.     return prefix
  121.  
  122.  
  123. # Is a path a symbolic link?
  124. # This will always return false on systems where amiga.lstat doesn't exist.
  125. # (or where S_ISLNK isn't defined)
  126. def islink(path):
  127.     try:
  128.         st = amiga.lstat(path)
  129.         return stat.S_ISLNK(st[stat.ST_MODE])
  130.     except (amiga.error, AttributeError):
  131.         return 0
  132.  
  133.  
  134. # Does a path exist?
  135. # This is false for dangling symbolic links.
  136.  
  137. def exists(path):
  138.     try:
  139.         st = amiga.stat(path)
  140.     except amiga.error:
  141.         return 0
  142.     return 1
  143.  
  144.  
  145. # Is a path an amiga directory?
  146. # This follows symbolic links, so both islink() and isdir() can be true
  147. # for the same path.
  148.  
  149. def isdir(path):
  150.     try:
  151.         st = amiga.stat(path)
  152.     except amiga.error:
  153.         return 0
  154.     return stat.S_ISDIR(st[stat.ST_MODE])
  155.  
  156.  
  157. # Is a path a regular file?
  158. # This follows symbolic links, so both islink() and isfile() can be true
  159. # for the same path.
  160.  
  161. def isfile(path):
  162.     try:
  163.         st = amiga.stat(path)
  164.     except amiga.error:
  165.         return 0
  166.     return stat.S_ISREG(st[stat.ST_MODE])
  167.  
  168.  
  169. # Are two filenames really pointing to the same file?
  170.  
  171. def samefile(f1, f2):
  172.     s1 = amiga.stat(f1)
  173.     s2 = amiga.stat(f2)
  174.     return samestat(s1, s2)
  175.  
  176.  
  177. # Are two open files really referencing the same file?
  178. # (Not necessarily the same file descriptor!)
  179.  
  180. def sameopenfile(fp1, fp2):
  181.     s1 = amiga.fstat(fp1)
  182.     s2 = amiga.fstat(fp2)
  183.     return samestat(s1, s2)
  184.  
  185.  
  186. # Are two stat buffers (obtained from stat, fstat or lstat)
  187. # describing the same file?
  188.  
  189. def samestat(s1, s2):
  190.     return s1[stat.ST_INO] == s2[stat.ST_INO] and \
  191.         s1[stat.ST_DEV] == s2[stat.ST_DEV]
  192.  
  193.  
  194. # Is a path a mount point? AMIGA: Is it a device name?
  195.  
  196. def ismount(path):
  197.     drive,rest = splitdrive(path)
  198.     if rest=='':
  199.         return 1
  200.     else:
  201.         return 0
  202.  
  203.  
  204. # Directory tree walk.
  205. # For each directory under top (including top itself),
  206. # func(arg, dirname, filenames) is called, where
  207. # dirname is the name of the directory and filenames is the list
  208. # files files (and subdirectories etc.) in the directory.
  209. # The func may modify the filenames list, to implement a filter,
  210. # or to impose a different order of visiting.
  211.  
  212. def walk(top, func, arg):
  213.     try:
  214.         names = amiga.listdir(top)
  215.     except amiga.error:
  216.         return
  217.     func(arg, top, names)
  218.     for name in names:
  219.         name = join(top, name)
  220.         if isdir(name) and not islink(name):
  221.             walk(name, func, arg)
  222.  
  223.  
  224. # Expand paths beginning with '~' or '~user'.
  225. # '~' means $HOME; '~user' means that user's home directory.
  226. # If the path doesn't begin with '~', or if the user or $HOME is unknown,
  227. # the path is returned unchanged (leaving error reporting to whatever
  228. # function is called with the expanded path as argument).
  229. # See also module 'glob' for expansion of *, ? and [...] in pathnames.
  230. # (A function should also be defined to do full *sh-style environment
  231. # variable expansion.)
  232.  
  233. def expanduser(path):
  234.     if path[:1] <> '~':
  235.         return path
  236.     i, n = 1, len(path)
  237.     while i < n and path[i] <> '/':
  238.         i = i+1
  239.     if i == 1:
  240.         if not amiga.environ.has_key('HOME'):
  241.             return path
  242.         userhome = amiga.environ['HOME']
  243.     else:
  244.         try:
  245.             import pwd
  246.             pwent = pwd.getpwnam(path[1:i])
  247.         except (KeyError,ImportError,SystemError):
  248.             return path            # ~user only works if pwd module works
  249.         userhome = pwent[5]
  250.     if userhome[-1:] == '/': i = i+1
  251.     return userhome + path[i:]
  252.  
  253.  
  254. # Expand paths containing shell variable substitutions.
  255. # This expands the forms $variable and ${variable} only.
  256. # Non-existant variables are left unchanged.
  257.  
  258. _varprog = None
  259.  
  260. def expandvars(path):
  261.     global _varprog
  262.     if '$' not in path:
  263.         return path
  264.     if not _varprog:
  265.         import regex
  266.         _varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)')
  267.     i = 0
  268.     while 1:
  269.         i = _varprog.search(path, i)
  270.         if i < 0:
  271.             break
  272.         name = _varprog.group(1)
  273.         j = i + len(_varprog.group(0))
  274.         if name[:1] == '{' and name[-1:] == '}':
  275.             name = name[1:-1]
  276.         if amiga.environ.has_key(name):
  277.             tail = path[j:]
  278.             path = path[:i] + amiga.environ[name]
  279.             i = len(path)
  280.             path = path + tail
  281.         else:
  282.             i = j
  283.     return path
  284.  
  285.  
  286. # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
  287. # It should be understood that this may change the meaning of the path
  288. # if it contains symbolic links!
  289. # Note: does nothing on Amiga because x/y//z is different than x/y/z.
  290.  
  291. def normpath(path):
  292.     return path
  293.  
  294.